package com.googlecode.archimedes.filegen.generator.freemarker;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.archimedes.filegen.controller.GenerationException;
import com.googlecode.archimedes.filegen.generator.AbstractGenerator;
import com.googlecode.archimedes.filegen.model.AbstractType;
import com.googlecode.archimedes.filegen.model.Abstractable;
import com.googlecode.archimedes.filegen.model.Application;
import com.googlecode.archimedes.filegen.model.Asset;
import com.googlecode.archimedes.filegen.model.Enumeration;
import com.googlecode.archimedes.util.ModelUtil;

import freemarker.template.SimpleHash;

/**
 * <p>
 * Right now i'm making this look exactly liek the Legacy example of VelocityApplicatonGenerator And later I'll customize and clean it up. This Class
 * generates a collection of files from an applicaiton model and a collection of templates. It uses a Generator to write each file individually to
 * avoid the messiness of looking ofr files and cleaning up the open OutputStream, etc....
 * </p>
 * <p>
 * Created: Jan 13, 2005
 * </p>
 * 
 * @author John Lema
 * @version $Id: FreeMarkerApplicationGenerator.java 2023 2006-02-18 01:16:42 +0000 (Sat, 18 Feb 2006) erik $
 */
public class FreeMarkerApplicationGenerator extends AbstractGenerator {

	private Log	log	= LogFactory.getLog(this.getClass().getName());

	// -------------- Main Methods ---------------------------------------------------------------
	/**
	 * This is an exact copy of the same method in VelocityApplicaitonGenerator It should be moved into a common class. Loop through the Collection of
	 * assets and attempt to generate based on the Template we have been passed.
	 * 
	 * @see com.tps.filegen.generator.AbstractGenerator#generate()
	 */
	public void generate() throws GenerationException {
		for (Asset asset : this.getAssets()) {

			// check to see if the template we are generating matches any assets
			if (this.getTemplate().getAllowedAssetClass().isInstance(asset)) {

				// check and see if our asset is abstractable and that the template
				// allows this
				if (asset instanceof Abstractable) {
					Abstractable abstractable = (Abstractable) asset;
					if (abstractable.isAbstract() && !getTemplate().isAbstractAllowed()) {
						log.info("The Asset [" + asset + "] is abstract and the template [" + getTemplate().getTemplateName() + "] does not allow abstract assets.");
						continue;
					}
				}

				// generate our code depending on what kind of asset we are working with
				if (asset instanceof AbstractType) {
					generateEntity((AbstractType) asset);
				} else if (asset instanceof Application) {
					generateApplication((Application) asset);
				} else if (asset instanceof Enumeration) {
					generateEnumeration((Enumeration) asset);
				}
			}
		}
	}

	/**
	 * This method creates all the files necessary for an Entity. Compare to the same method name in VelocityApplicationGenerator
	 * 
	 * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateEntity()
	 */
	protected void generateEnumeration(Enumeration anEnum) throws GenerationException {

		// SimpleHash is FreeMarker specific
		SimpleHash dataModel = new SimpleHash();

		// Entity templates need an App and an Entity
		dataModel.put("app", findApp());
		dataModel.put("bo", anEnum);
		dataModel.put("util", new ModelUtil());
		dataModel.put("tf", getTemplate()); // not sure if this is needed any more

		String subpath = findApp().getBasePackage();
		if (anEnum.getPackage() != null) {
			subpath += "." + anEnum.getPackage();
		}

		FreeMarkerGenerator.generate(this, anEnum.getName(), this.getTemplate(), dataModel, dotToPath(subpath));
	}

	/**
	 * This method creates all the files necessary for an Entity. Compare to the same method name in VelocityApplicationGenerator
	 * 
	 * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateEntity()
	 */
	protected void generateEntity(AbstractType asset) throws GenerationException {

		// SimpleHash is FreeMarker specific
		SimpleHash dataModel = new SimpleHash();

		// Entity templates need an App and an Entity
		dataModel.put("app", findApp());
		dataModel.put("bo", asset);
		dataModel.put("util", new ModelUtil());
		dataModel.put("tf", getTemplate()); // not sure if this is needed any more

		String subpath = findApp().getBasePackage();
		if (asset.getPackage() != null) {
			subpath += "." + asset.getPackage();
		}

		FreeMarkerGenerator.generate(this, asset.getEntityName(), this.getTemplate(), dataModel, dotToPath(subpath));
	}

	/**
	 * This method creates all the files necessary for an Application. Compare to the same method name in VelocityApplicationGenerator
	 * 
	 * @see com.tps.filegen.generator.velocity.VelocityApplicationGenerator#generateApplication()
	 */
	protected void generateApplication(Application app) throws GenerationException {

		SimpleHash dataModel = new SimpleHash();

		// SimpleHash is FreeMarker specific
		dataModel.put("app", app);

		// Entity templates need an App and an Entity
		dataModel.put("bos", app.getEntities());
		dataModel.put("util", new ModelUtil());
		dataModel.put("tf", getTemplate()); // not sure if this is needed any more
		FreeMarkerGenerator.generate(this, "", this.getTemplate(), dataModel);
	}

	// ---------------------Utility Methods --------------------------------------------------------------

	protected Application findApp() throws GenerationException {
		for (Asset asset : getAssets()) {
			if (asset instanceof Application) {
				return (Application) asset;
			}
		}

		throw new GenerationException("Unable to find an Application object.");
	}
}
